home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 1 / Cream of the Crop 1.iso / PROGRAM / SPAWNO41.ARJ / SWAP_EMS.ASM < prev    next >
Assembly Source File  |  1991-11-16  |  11KB  |  390 lines

  1. IFNDEF __TPINC
  2.     NAME    swap_ems
  3.     TITLE    SPAWNO EMS swapping code
  4.     PAGE    60,132
  5.  
  6. ;-----------------------------------
  7. ; (c) Copyright 1990,1991 Ralf Brown  All Rights Reserved
  8. ; This file may be redistributed as a part of the complete SPAWNO package,
  9. ; under its distribution conditions
  10. ;
  11. ;  SPAWNO v4.00
  12. ;    Overlaying spawnv()
  13. ;
  14. ;  File: SWAP_EMS
  15. ;-----------------------------------
  16.  
  17. __BSS__ equ 1                ; yes, we are using uninitialized storage
  18.     INCLUDE RULES.ASI        ; define the various standard macros
  19.     INCLUDE SPAWNO.INC
  20.  
  21.     Header@                ; set up segment and group definitions
  22. ENDIF ;ndef __TPINC
  23.  
  24. ;-----------------------------------------------------------
  25. ; data with relocatable items
  26.  
  27. JSeg@
  28.  
  29. public@ __SPAWNO_FUNCS_EMS
  30. __SPAWNO_FUNCS_EMS label byte
  31.     dw    spawno_init_ems        ; called to determine whether to swap to EMS
  32.     dw    write_block_ems        ; called to write out memory
  33.     dw    spawno_swapdone_ems    ; called when all memory written out
  34.     dw    spawno_swapin_ems    ; called when ready to read back memory
  35.     dw    read_ems        ; called to read back a section of memory
  36.     dw    spawno_finish_ems    ; called to clean up at very end of swap
  37.     dw    $ems_overlay        ; address of code to append to resident stub
  38.     dw    ems_overlay_size    ; total size of code to be appended
  39.     dw    ems_overlay_res        ; number of bytes which must stay resident
  40.  
  41. JSegEnd@
  42.  
  43. ;-----------------------------------------------------------
  44. ; initialized data
  45.  
  46. DSeg@
  47.  
  48. EMM_name    DB "EMMXXXX0"
  49.  
  50. IFNDEF RBcomm
  51. PubSym@ __spawn_ems,<DB 1>,__CDECL__    ; are we allowed to swap to EMS?
  52. ELSE
  53. ExtSym@ __spawn_ems,BYTE,__CDECL__
  54. ENDIF ;RBcomm
  55. DSegEnd@
  56.  
  57. ;----------------------------------------------------------------
  58. ; uninitialized data storage area
  59.  
  60. BSeg@
  61.  
  62. ems_page_num    dw ?            ; current page number for EMS handle
  63. ems_page_offset    dw ?            ; offset (in para) withing page
  64.  
  65. ems_page_num$    dw ?            ; page number after reading in PSP
  66. ems_page_offset$ dw ?            ; offset (in bytes) after reading in PSP
  67.  
  68. BSegEnd@
  69.  
  70. ;----------------------------------------------------------------
  71.  
  72. CSeg@
  73.  
  74. ;----------------------------------------------------------------
  75. ; section of code to append to the common code when using EMS for
  76. ; swapping
  77. ;
  78. ; on entry,
  79. ;    DX = segment at which to start reloading memory
  80. ;    CS = DS = segment of program's PSP
  81. ;    AX, BX, CX, SI, DI, ES unpredictable
  82. ; at exit:
  83. ;    SS:SP must be preserved, but all other registers can be destroyed
  84. ; The device-specific code is always entered at the very beginning and
  85. ; must exit either by falling off the end or by branching to "abort_offset"
  86. ; bytes prior to its beginning with DS=CS (the latter only if it detects
  87. ; an error from which it cannot recover).
  88. ;
  89. $ems_overlay proc far
  90. ems_reloc_factor equ (offset $ems_overlay - resident_addr)
  91.     ASSUME    DS:NOTHING
  92.     mov    es,dx            ; ES <- seg at which to start loading
  93.     ASSUME    ES:NOTHING
  94.     xor    bx,bx            ; start on logical page 0
  95.     mov    dx,0            ; DX <- EMS handle (will be patched)
  96. $ems_handle equ word ptr ($-2)
  97. ems_reload_loop:
  98.     mov    ax,4400h        ; map logical page into physical page 0
  99.     int    67h
  100.     or    ah,ah            ; was "map" call successful?
  101.     jnz short ($ems_overlay - abort_offset)  ; quit if not
  102.     mov    ax,0            ; AX <- EMS page frame seg (will patch)
  103. page_frame_seg equ word ptr ($-2)
  104.     mov    ds,ax            ; DS -> page frame
  105.     ASSUME    DS:NOTHING
  106.     mov    cx,2000h        ; 16K bytes = 8K words
  107. $ems_partial equ word ptr ($-2)
  108.     xor    si,si            ; source offset is 0
  109.     xor    di,di            ; dest offset is 0
  110.     rep    movsw
  111.     jmp short copied_page        ; flush prefetch queue
  112. ems_overlay_res equ $ - $ems_overlay
  113. ;
  114. ; everything beyond this point may be overwritten by the child program, since
  115. ; the first read above will restore it back to memory
  116. ;
  117. $ems_pages dw    0            ; number of pages, excluding partial last
  118.                     ; will be filled in before copy to PSP
  119. copied_page:
  120.     inc    bx            ; go to next logical page
  121.     mov    ax,es            ; move 16K higher in memory
  122.     add    ax,400h
  123.     mov    es,ax
  124.     dec    word ptr cs:($ems_pages - ems_reloc_factor)
  125.     jg    ems_reload_loop        ; if not yet last, go do another full page
  126.     mov    word ptr cs:($ems_partial - ems_reloc_factor),0
  127. $ems_partial_size equ word ptr ($-2)
  128.     jz    ems_reload_loop        ; loop one last time if count reached 0
  129. ;
  130. ; exit by falling out of this subroutine
  131. ;
  132. $ems_overlay endp
  133.  
  134. ems_overlay_size equ $ - $ems_overlay
  135.  
  136. ;----------------------------------------------------------------
  137. ; entry: AX = start segment within EMS page frame
  138. ;     ES = conventional-memory transfer segment
  139. ; exit:     DS, ES = source, destination of copy
  140. ;     DX = new conventional-memory transfer address
  141. ;----------------------------------------------------------------
  142. set_segment_read proc near
  143.     mov    ds,ax            ; AX = start segment in EMS page frame
  144.     ASSUME    DS:NOTHING
  145.     mov    dx,es
  146.     ret
  147. set_segment_read endp
  148.  
  149. set_segment_write proc near
  150.     mov    dx,es
  151.     mov    ds,dx
  152.     mov    es,ax            ; AX = start segment in EMS page frame
  153.     ret
  154. set_segment_write endp
  155.  
  156. ;----------------------------------------------------------------
  157. ; enter: AX=starting segment
  158. ;     BX = handle
  159. ;     DX=num paras
  160. ; return: CF clear on success, set if failed
  161. ;      AX, BX, CX, DX, ES destroyed
  162. ;----------------------------------------------------------------
  163. read_ems proc near
  164.     ASSUME    DS:DGROUP
  165.     mov    cx,offset __TEXT:set_segment_read
  166.     jmp short transfer_EMS
  167. read_ems endp
  168.  
  169. ;----------------------------------------------------------------
  170. ; entry: AX = starting segment
  171. ;     BX = handle
  172. ;     DX = number of paragraphs
  173. ; return: CF clear on success, set if failed
  174. ;      AX, BX, CX, DX, ES destroyed
  175. ;----------------------------------------------------------------
  176. write_block_ems proc near
  177.     mov    cx,offset __TEXT:set_segment_write
  178. transfer_EMS:
  179.     push    bp
  180.     mov    bp,bx            ; store handle
  181.     ASSUME    DS:DGROUP
  182.     mov    es,ax
  183.     ASSUME    ES:NOTHING
  184.     push    di
  185.     push    si
  186.     xchg    cx,dx
  187. xfer_ems_loop:
  188.     push    dx
  189.     mov    ax,4400h        ; map physical page 0
  190.     mov    bx,ems_page_num
  191.     mov    dx,bp            ; DX <- handle
  192.     int    67h            ; map in the appropriate EMS page
  193.     or    ah,ah
  194.     jnz    EMS_mapping_failed
  195.     mov    bx,ems_page_offset
  196.     mov    dx,bx
  197.     sub    bx,400h            ; 1024 paragraphs in a 16K EMS page
  198.     neg    bx            ; adjust for doing sub the wrong way
  199.     cmp    bx,cx
  200.     jbe    xfer_ems_fullpage
  201.     mov    bx,cx
  202.     add    ems_page_offset,bx
  203.     jmp short xfer_ems_do_it
  204. xfer_ems_fullpage:
  205.     xor    ax,ax
  206.     mov    ems_page_offset,ax
  207.     inc    ems_page_num
  208. xfer_ems_do_it:
  209.     mov    ax,page_frame_seg
  210.     add    ax,dx
  211.     cmp    ax,ax            ; set ZF to indicate success
  212. EMS_mapping_failed:
  213.     pop    dx
  214.     jnz    xfer_ems_failed
  215.     push    ds
  216.     push    dx
  217.     call    dx            ; set DS, ES, and DX
  218.     ASSUME    DS:NOTHING,ES:NOTHING
  219.     xor    si,si
  220.     xor    di,di
  221.     push    cx
  222.     mov    cx,bx
  223.     shl    cx,1
  224.     shl    cx,1
  225.     shl    cx,1            ; paragraphs to words
  226.     cld
  227.     rep    movsw            ; copy as much memory as we can
  228.     pop    cx
  229.     add    dx,bx
  230.     mov    es,dx            ; move higher in mem by amount copied
  231.     pop    dx
  232.     pop    ds
  233.     ASSUME    DS:DGROUP
  234.     sub    cx,bx            ; update amount remaining
  235.     jnz    xfer_ems_loop
  236.     clc                ; tell caller we succeeded
  237. xfer_ems_done:
  238.     pop    si
  239.     pop    di
  240.     pop    bp
  241.     ret
  242.  
  243. xfer_ems_failed:
  244.     stc                ; tell caller we failed
  245.     jmp    xfer_ems_done
  246. write_block_ems endp
  247.  
  248. ;----------------------------------------------------------------
  249. ; return the number of EMS pages which are available (0 if no EMS) in AX
  250. ;
  251. IFDEF RBcomm
  252. public _EMS_available
  253. ENDIF ;RBcomm
  254.  
  255. _EMS_available proc near
  256.     ASSUME    DS:DGROUP
  257.     push    es
  258.     push    si
  259.     push    di
  260.     mov    ax,3567h
  261.     int    21h            ; get vector for EMS driver
  262.     mov    di,10            ; ES:DI -> driver name
  263.     mov    si,offset DGROUP:EMM_name
  264.     mov    cx,8            ; length EMM_name
  265.     cld
  266.     xor    ax,ax            ; assume no match
  267.     repz    cmps EMM_name,byte ptr es:[di]
  268.     jnz    EMS_avail_done
  269.     mov    ah,42h
  270.     int    67h
  271.     or    ah,ah            ; was call successful?
  272.     mov    ax,bx            ; assume yes, return # of pages available
  273.     jz    EMS_avail_done
  274.     xor    ax,ax            ; nope, so return zero
  275. EMS_avail_done:
  276.     pop    di
  277.     pop    si
  278.     pop    es
  279.     ret
  280. _EMS_available endp
  281.  
  282. ;----------------------------------------------------------------
  283. ; Determine whether able to swap to EMS, and prepare for swapping to EMS
  284. ;    if able.
  285. ; on entry:
  286. ;    AX = total number of paragraphs to swap out
  287. ;    DX = number of paragraphs in PSP block to swap out
  288. ; return: CF set on error
  289. ;       CF clear if able to swap
  290. ;        AX = handle
  291. ;----------------------------------------------------------------
  292. spawno_init_ems proc near
  293.     ASSUME    DS:DGROUP
  294.     cmp    __spawn_ems@,0        ; are we allowed to use EMS?
  295.     je    no_EMS            ; if not, try next method
  296.     push    ax            ; remember total paragraphs required
  297.     mov    cx,(16*1024)        ; 16K per page, but 16 bytes per para
  298.     mov    ax,16            ; 16 bytes per paragraph
  299.     push    ax
  300.     mul    dx            ; paragraphs to bytes
  301.     div    cx            ; DX:AX bytes to EMS pages
  302.     mov    ems_page_num$,ax
  303.     mov    ems_page_offset$,dx
  304.     or    dx,dx            ; partial last page?
  305.     jne    got_last_page
  306.     dec    ax            ; if not, say we have a "partial" last
  307.     mov    dx,(16*1024)        ;   page of 16K
  308. got_last_page:
  309.     mov    $ems_pages,ax
  310.     mov    $ems_partial_size,dx
  311.     xor    ax,ax
  312.     mov    ems_page_num,ax
  313.     mov    ems_page_offset,ax
  314.     pop    dx            ; DX <- 16
  315.     pop    ax            ; get back total paragraphs required
  316.     mul    dx            ; paragraphs to bytes
  317.     div    cx            ; DX:AX bytes to EMS pages
  318.     or    dx,dx
  319.     jz    no_partial_page_ems
  320.     inc    ax
  321. no_partial_page_ems:
  322.     push    ax            ; remember required number of pages
  323.     call    _EMS_available        ; find out how many EMS pages are free
  324.     pop    cx            ; get back required number of pages
  325.     cmp    ax,cx            ; enough EMS memory for swapping?
  326.     jb    no_EMS            ; if not, swap to disk
  327.     mov    ah,41h            ; get EMS page frame segment
  328.     int    67h
  329.     or    ah,ah            ; was call successful
  330.     jnz    no_EMS            ; swap to disk if not
  331.     mov    page_frame_seg,bx    ; store page frame seg in swap-in code
  332.     mov    ah,43h            ; allocate EMS for swapping
  333.     mov    bx,cx            ; BX <- total number of EMS pages needed
  334.     int    67h
  335.     or    ah,ah
  336.     jnz    no_EMS            ; if error, try next method
  337.     mov    ah,47h            ; save mapping context for handle DX
  338.     int    67h
  339.     mov    ax,dx            ; return the EMS handle
  340.     mov    $ems_handle,ax
  341.     clc
  342.     ret
  343. no_EMS:
  344.     stc
  345.     ret
  346. spawno_init_ems endp
  347.  
  348. ;----------------------------------------------------------------
  349. ; Clean up at end of spawn.
  350. ; entry: AX = handle returned by spawno_init_*
  351. ;----------------------------------------------------------------
  352. spawno_finish_ems proc near
  353.     assume    DS:DGROUP,ES:NOTHING
  354.     mov    dx,ax            ; DX <- handle
  355.     mov    ah,48h            ; restore mapping context
  356.     int    67h
  357.     mov    ah,45h
  358.     int    67h            ; free EMS handle and memory
  359.     ;
  360.     ; assume the free works, since there's not much we can do if it doesn't
  361.     ;
  362. spawno_swapdone_ems:            ; don't need to do anything after
  363.                     ;   writing out the memory, so piggy-
  364.                     ;   back an empty subroutine onto an
  365.                     ;   existing return instruction
  366.     ret
  367. spawno_finish_ems endp
  368.  
  369. ;----------------------------------------------------------------
  370. ; Prepare to read back the swapped-out program's memory
  371. ; entry: AX = handle returned by spawno_init_ems
  372. ;----------------------------------------------------------------
  373. spawno_swapin_ems proc near
  374.     ASSUME    DS:DGROUP
  375.     mov    ax,ems_page_num$
  376.     mov    ems_page_num,ax
  377.     mov    ax,ems_page_offset$
  378.     mov    cl,4
  379.     shr    ax,cl
  380.     mov    ems_page_offset,ax
  381.     ret
  382. spawno_swapin_ems endp
  383.  
  384. CSegEnd@
  385.  
  386. IFNDEF __TPINC
  387.     NOWARN OPI
  388.     END
  389. ENDIF
  390.